package cn.lingyangwl.framework.security;

import cn.lingyangwl.framework.security.xss.config.SecurityXssProperties;
import cn.lingyangwl.framework.security.xss.core.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.PostConstruct;
import java.util.List;

/**
 * @author shenguangyang
 */
@Slf4j
@AutoConfiguration
@ConditionalOnClass(ObjectMapper.class)
@RequiredArgsConstructor
@EnableConfigurationProperties({SecurityXssProperties.class})
@ConditionalOnProperty(prefix = SecurityXssProperties.PREFIX, name = "enabled",
        havingValue = "true", matchIfMissing = true)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@AutoConfigureBefore(JacksonAutoConfiguration.class)
public class LySecurityXssAutoConfiguration implements WebMvcConfigurer {
    private final SecurityXssProperties xssProperties;

    @PostConstruct
    public void init() {
        log.info("init {}", this.getClass().getName());
    }

    @Bean
    @ConditionalOnMissingBean
    public XssCleaner xssCleaner(SecurityXssProperties properties) {
        return new DefaultXssCleaner(properties);
    }

    @Bean
    public FormXssClean formXssClean(SecurityXssProperties properties,
                                     XssCleaner xssCleaner) {
        return new FormXssClean(properties, xssCleaner);
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer xssJacksonCustomizer(
            SecurityXssProperties properties, XssCleaner xssCleaner) {
        return builder -> builder.deserializerByType(String.class, new JacksonXssClean(properties, xssCleaner));
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> patterns = xssProperties.getPathPatterns();
        if (patterns.isEmpty()) {
            patterns.add("/**");
        }
        XssCleanServletInterceptor interceptor = new XssCleanServletInterceptor(xssProperties);
        registry.addInterceptor(interceptor).addPathPatterns(patterns)
                .excludePathPatterns(xssProperties.getPathExcludePatterns()).order(Ordered.LOWEST_PRECEDENCE);
    }
}
